94

約 105000 行と 30 列のデータセットがあります。数値に割り当てたいカテゴリ変数があります。Excel では、おそらく何かを実行して入力しVLOOKUPます。

で同じことを行うにはどうすればよいRですか?

基本的に、私が持っているのはHouseType変数であり、を計算する必要がありますHouseTypeNo。サンプルデータを次に示します。

HouseType HouseTypeNo
Semi            1
Single          2
Row             3
Single          2
Apartment       4
Apartment       4
Row             3
4

9 に答える 9

132

私があなたの質問を正しく理解しているなら、ここにExcelVLOOKUPと同等のことをして、以下を使って記入する4つの方法がありますR

# load sample data from Q
hous <- read.table(header = TRUE, 
                   stringsAsFactors = FALSE, 
text="HouseType HouseTypeNo
Semi            1
Single          2
Row             3
Single          2
Apartment       4
Apartment       4
Row             3")

# create a toy large table with a 'HouseType' column 
# but no 'HouseTypeNo' column (yet)
largetable <- data.frame(HouseType = as.character(sample(unique(hous$HouseType), 1000, replace = TRUE)), stringsAsFactors = FALSE)

# create a lookup table to get the numbers to fill
# the large table
lookup <- unique(hous)
  HouseType HouseTypeNo
1      Semi           1
2    Single           2
3       Row           3
5 Apartment           4

表の値を使用してをHouseTypeNo入力する4つの方法を次に示します。largetablelookup

最初mergeにベースで:

# 1. using base 
base1 <- (merge(lookup, largetable, by = 'HouseType'))

ベースに名前付きベクトルを使用する2番目のメソッド:

# 2. using base and a named vector
housenames <- as.numeric(1:length(unique(hous$HouseType)))
names(housenames) <- unique(hous$HouseType)

base2 <- data.frame(HouseType = largetable$HouseType,
                    HouseTypeNo = (housenames[largetable$HouseType]))

第三に、plyrパッケージの使用:

# 3. using the plyr package
library(plyr)
plyr1 <- join(largetable, lookup, by = "HouseType")

第四に、sqldfパッケージを使用する

# 4. using the sqldf package
library(sqldf)
sqldf1 <- sqldf("SELECT largetable.HouseType, lookup.HouseTypeNo
FROM largetable
INNER JOIN lookup
ON largetable.HouseType = lookup.HouseType")

の一部の家タイプがにlargetable存在しない可能性がある場合lookupは、左結合が使用されます。

sqldf("select * from largetable left join lookup using (HouseType)")

他のソリューションへの対応する変更も必要になります。

それはあなたがやりたかったことですか?どの方法が好きか教えてください。解説を追加します。

于 2013-03-09T05:51:00.440 に答える
33

も使用できると思いますmatch()

largetable$HouseTypeNo <- with(lookup,
                     HouseTypeNo[match(largetable$HouseType,
                                       HouseType)])

の順序をスクランブルしても、これは機能しlookupます。

于 2015-10-20T20:34:29.560 に答える
11

qdapTools::lookupまた、 or 省略形の二項演算子を使用するのも好き%l%です。Excel vlookup と同じように機能しますが、列番号ではなく名前引数を受け入れます

## Replicate Ben's data:
hous <- structure(list(HouseType = c("Semi", "Single", "Row", "Single", 
    "Apartment", "Apartment", "Row"), HouseTypeNo = c(1L, 2L, 3L, 
    2L, 4L, 4L, 3L)), .Names = c("HouseType", "HouseTypeNo"), 
    class = "data.frame", row.names = c(NA, -7L))


largetable <- data.frame(HouseType = as.character(sample(unique(hous$HouseType), 
    1000, replace = TRUE)), stringsAsFactors = FALSE)


## It's this simple:
library(qdapTools)
largetable[, 1] %l% hous
于 2013-10-22T12:50:53.287 に答える
6

@Benの回答の解決策#2は、他のより一般的な例では再現できません。HouseTypeこの例では、ユニークなインhousesが昇順で表示されるため、たまたま正しいルックアップが得られます。これを試して:

hous <- read.table(header = TRUE,   stringsAsFactors = FALSE,   text="HouseType HouseTypeNo
  Semi            1
  ECIIsHome       17
  Single          2
  Row             3
  Single          2
  Apartment       4
  Apartment       4
  Row             3")

largetable <- data.frame(HouseType = as.character(sample(unique(hous$HouseType), 1000, replace = TRUE)), stringsAsFactors = FALSE)
lookup <- unique(hous)

ベンズソリューション#2が与える

housenames <- as.numeric(1:length(unique(hous$HouseType)))
names(housenames) <- unique(hous$HouseType)
base2 <- data.frame(HouseType = largetable$HouseType,
                    HouseTypeNo = (housenames[largetable$HouseType]))

いつ

unique(base2$HouseTypeNo[ base2$HouseType=="ECIIsHome" ])
[1] 2

ルックアップテーブルの正解が17の場合

それを行う正しい方法は

 hous <- read.table(header = TRUE,   stringsAsFactors = FALSE,   text="HouseType HouseTypeNo
      Semi            1
      ECIIsHome       17
      Single          2
      Row             3
      Single          2
      Apartment       4
      Apartment       4
      Row             3")

largetable <- data.frame(HouseType = as.character(sample(unique(hous$HouseType), 1000, replace = TRUE)), stringsAsFactors = FALSE)

housenames <- tapply(hous$HouseTypeNo, hous$HouseType, unique)
base2 <- data.frame(HouseType = largetable$HouseType,
  HouseTypeNo = (housenames[largetable$HouseType]))

ルックアップが正しく実行されるようになりました

unique(base2$HouseTypeNo[ base2$HouseType=="ECIIsHome" ])
ECIIsHome 
       17

ベンの回答を編集しようとしましたが、理解できない理由で拒否されました。

于 2013-12-09T19:08:47.863 に答える
5

で始まります:

houses <- read.table(text="Semi            1
Single          2
Row             3
Single          2
Apartment       4
Apartment       4
Row             3",col.names=c("HouseType","HouseTypeNo"))

...使用できます

as.numeric(factor(houses$HouseType))

... 家の種類ごとに一意の番号を付けます。ここで結果を見ることができます:

> houses2 <- data.frame(houses,as.numeric(factor(houses$HouseType)))
> houses2
  HouseType HouseTypeNo as.numeric.factor.houses.HouseType..
1      Semi           1                                    3
2    Single           2                                    4
3       Row           3                                    2
4    Single           2                                    4
5 Apartment           4                                    1
6 Apartment           4                                    1
7       Row           3                                    2

...そのため、行の数字は異なりますが(因子はアルファベット順に並べられているため)、パターンは同じです。

(編集:この回答の残りのテキストは実際には冗長です。チェックすることをread.table()思いついたのですが、最初にデータフレームに読み込まれたときに、houses$HouseType がすでに要因になっていることがわかりました)。

ただし、HouseType を係数に変換するだけで、HouseTypeNo と同じ利点が得られますが、家のタイプには番号が付けられているのではなく名前が付けられているため、解釈が容易になります。

> houses3 <- houses
> houses3$HouseType <- factor(houses3$HouseType)
> houses3
  HouseType HouseTypeNo
1      Semi           1
2    Single           2
3       Row           3
4    Single           2
5 Apartment           4
6 Apartment           4
7       Row           3
> levels(houses3$HouseType)
[1] "Apartment" "Row"       "Semi"      "Single"  
于 2013-03-08T21:30:09.483 に答える
5

mapvalues()plyr パッケージから使用できます。

初期データ:

dat <- data.frame(HouseType = c("Semi", "Single", "Row", "Single", "Apartment", "Apartment", "Row"))

> dat
  HouseType
1      Semi
2    Single
3       Row
4    Single
5 Apartment
6 Apartment
7       Row

ルックアップ/横断歩道テーブル:

lookup <- data.frame(type_text = c("Semi", "Single", "Row", "Apartment"), type_num = c(1, 2, 3, 4))
> lookup
  type_text type_num
1      Semi        1
2    Single        2
3       Row        3
4 Apartment        4

新しい変数を作成します。

dat$house_type_num <- plyr::mapvalues(dat$HouseType, from = lookup$type_text, to = lookup$type_num)

または、単純な置換の場合、長いルックアップ テーブルの作成をスキップして、これを 1 つのステップで直接行うことができます。

dat$house_type_num <- plyr::mapvalues(dat$HouseType,
                                      from = c("Semi", "Single", "Row", "Apartment"),
                                      to = c(1, 2, 3, 4))

結果:

> dat
  HouseType house_type_num
1      Semi              1
2    Single              2
3       Row              3
4    Single              2
5 Apartment              4
6 Apartment              4
7       Row              3
于 2015-10-20T20:37:18.243 に答える
3

mergeルックアップ テーブルで主キー制約が適用されていない場合、またはall.x = T.

トラブルに巻き込まれないようにして安全に検索するために、2 つの戦略を提案します。

最初の 1 つは、ルックアップ キーで多数の重複行をチェックすることです。

safeLookup <- function(data, lookup, by, select = setdiff(colnames(lookup), by)) {
  # Merges data to lookup making sure that the number of rows does not change.
  stopifnot(sum(duplicated(lookup[, by])) == 0)
  res <- merge(data, lookup[, c(by, select)], by = by, all.x = T)
  return (res)
}

これにより、ルックアップ データセットを使用する前に重複排除が強制されます。

baseSafe <- safeLookup(largetable, house.ids, by = "HouseType")
# Error: sum(duplicated(lookup[, by])) == 0 is not TRUE 

baseSafe<- safeLookup(largetable, unique(house.ids), by = "HouseType")
head(baseSafe)
# HouseType HouseTypeNo
# 1 Apartment           4
# 2 Apartment           4
# ...

2 番目のオプションは、ルックアップ データセットから最初に一致する値を取得して、Excel の動作を再現することです。

firstLookup <- function(data, lookup, by, select = setdiff(colnames(lookup), by)) {
  # Merges data to lookup using first row per unique combination in by.
  unique.lookup <- lookup[!duplicated(lookup[, by]), ]
  res <- merge(data, unique.lookup[, c(by, select)], by = by, all.x = T)
  return (res)
}

baseFirst <- firstLookup(largetable, house.ids, by = "HouseType")

lookupこれらの関数は、複数の列を追加するため、 とは少し異なります。

于 2016-05-21T23:03:54.827 に答える
2

パッケージは次のlookup場所で使用できます。

library(lookup)
# reference data
hous <- data.frame(HouseType=c("Semi","Single","Row","Single","Apartment","Apartment","Row"),
                   HouseTypeNo=c(1,2,3,2,4,4,3))
# new large data with HouseType but no HouseTypeNo
largetable <- data.frame(HouseType = sample(unique(hous$HouseType), 1000, replace = TRUE))

# vector approach
largetable$num1 <- lookup(largetable$HouseType, hous$HouseType, hous$HouseTypeNo)
# dataframe approach
largetable$num2 <- vlookup(largetable$HouseType, hous, "HouseType", "HouseTypeNo")

head(largetable)
#   HouseType num1 num2
# 1      Semi    1    1
# 2      Semi    1    1
# 3 Apartment    4    4
# 4      Semi    1    1
# 5    Single    2    2
# 6    Single    2    2
于 2021-04-14T16:18:32.217 に答える