Я попробовал 3 компилятора: MS Visual Studio 2012, gcc481 и Intel icl 13.1. Все они предупреждают, когда вы указываете. Я обнаружил, что gcc и MS автоматически генерируют код инициализации для tmp1, даже когда они предупреждают об отсутствии инициализации. Компилятор MS генерирует нежелательный доступ к памяти: movaps xmm0,xmmword ptr [rsp]
. Gcc генерирует более эффективный xorps xmm0,xmm0
. Поэтому в случае gcc добавление tmp1=_mm_setzero_ps()
устраняет предупреждение и создает точно такой же код, как и без него. В случае MS добавление tmp1=_mm_setzero_ps()
делает код короче и, вероятно, быстрее. Только компилятор Intel достаточно умен, чтобы избежать ненужной инициализации. Ниже приведено возможное обходное решение для компиляторов MS и gcc:
__m128 tmp1 = _mm_loadh_pi(_mm_load_ps (src), (__m64*)(src + 4));
Генерация кода:
movaps xmm0,xmmword ptr [rcx]
movhps xmm0,qword ptr [rcx+10h]
Он выглядит короче, но его следует сравнивать, чтобы убедиться, что он быстрее.
09/12/2013: тестовый код для различных идей подавления предупреждений:
#include <xmmintrin.h>
#include <stdint.h>
#include <stdio.h>
//---------------------------------------------------------------------------
// original code from http://download.intel.com/design/PentiumIII/sml/24504301.pdf
__m128 func1 (float *src)
{
__m128 tmp1;
tmp1 = _mm_loadh_pi(_mm_loadl_pi(tmp1, (__m64*)(src)), (__m64*)(src+ 4));
return tmp1;
}
//---------------------------------------------------------------------------
// original code plus tmp1 initialization
__m128 func2 (float *src)
{
__m128 tmp1 = _mm_loadh_pi(_mm_loadl_pi (_mm_setzero_ps (), (__m64*)(src)), (__m64*)(src + 4));
return tmp1;
}
//---------------------------------------------------------------------------
// use redundant load to eliminate warning
__m128 func3 (float *src)
{
__m128 tmp1 = _mm_loadh_pi(_mm_load_ps (src), (__m64*)(src + 4));
return tmp1;
}
//---------------------------------------------------------------------------
static void dump (void *data)
{
float *f16 = data;
int index;
for (index = 0; index < 4; index++)
printf ("%g ", f16 [index]);
printf ("\n");
}
//---------------------------------------------------------------------------
int main (void)
{
float f [8] = {1, 2, 3, 4, 5, 6, 7, 8};
__m128 tmp;
tmp = func1 (f);
dump (&tmp);
tmp = func2 (f);
dump (&tmp);
tmp = func3 (f);
dump (&tmp);
return 0;
}
команды сборки:
gcc -O3 -Wall -Wfatal-errors sample.c -osample.exe
objdump -Mintel --disassemble sample.exe > disasm.txt
cl -Ox -Zi -W4 sample.c
dumpbin -disasm -symbols sample.exe > disasm.txt
icl -Ox -Zi sample.c
dumpbin -disasm -symbols sample.exe > disasm.txt
Как насчет использования Reduce
с dplyr::coalesce
?
library(dplyr)
df <- data.frame(grp_A = c(13, NA, NA, NA, NA, 20, NA),
grp_B = c(NA, 59, 66, NA, NA, NA, NA),
grp_C = c(NA, NA, NA, 23, 42, NA, NA))
mutate(df, value = Reduce(coalesce, df))
Результат:
grp_A grp_B grp_C value
1 13 NA NA 13
2 NA 59 NA 59
3 NA 66 NA 66
4 NA NA 23 23
5 NA NA 42 42
6 20 NA NA 20
7 NA NA NA NA
Другой вариант - использовать rowSums
:
df$value <- rowSums(df, na.rm = T)
df[df$value == 0, ] <- NA
[ 1111] Кроме того, с точки зрения производительности, базовое Reduce
решение представляется наиболее эффективным:
microbenchmark::microbenchmark(
Reduce = Reduce(coalesce, df),
purrr = purrr::reduce(df, coalesce),
rowMeans = rowMeans(df,na.rm=T),
rowSums = rowSums(df, na.rm = T),
cbind = df[cbind(1:nrow(df), max.col(!is.na(df)))],
times = 1000
)
Unit: microseconds
expr min lq mean median uq max neval cld
Reduce 83.507 107.2095 145.4134 121.4320 137.8410 12190.845 1000 a
purrr 205.667 269.1175 357.5908 304.8540 342.4135 24316.051 1000 b
rowMeans 129.089 159.3555 196.1438 174.4890 194.9095 5481.523 1000 a
rowSums 129.454 157.1680 197.2731 173.5775 196.0035 7685.874 1000 a
cbind 267.294 331.8385 408.3179 368.4860 410.2400 4533.050 1000 b
База R rowMeans
df$new=rowMeans(df,na.rm=T)
df
grp_A grp_B grp_C new
1 13 NA NA 13
2 NA 59 NA 59
3 NA 66 NA 66
4 NA NA 23 23
5 NA NA 42 42
6 20 NA NA 20
7 NA NA NA NaN
Нет необходимости использовать apply
, поскольку для каждой строки у вас будет только одно значение, отличное от NA, мы можем получить это значение, используя max.col
, не беспокоясь о связях.
df$value <- df[cbind(1:nrow(df), max.col(!is.na(df)))]
df
# grp_A grp_B grp_C value
#1 13 NA NA 13
#2 NA 59 NA 59
#3 NA 66 NA 66
#4 NA NA 23 23
#5 NA NA 42 42
#6 20 NA NA 20
#7 NA NA NA NA
max.col
дает нам индекс номера столбца, который имеет максимальное значение для каждой строки, и, поскольку мы переносим его в !is.na
, он даст нам индекс TRUE
.
max.col(!is.na(df))
#[1] 1 2 2 3 3 1 2
Причина, по которой вы apply
не сработали, заключается в том, что в вашем последнем ряду было все NA
с, и x[!is.na(x)]
не сработал. Если вы удалите эту строку и запустите свою функцию, она будет работать
apply(df[-7, ], 1,function(x) x[!is.na(x)])
# 1 2 3 4 5 6
#13 59 66 23 42 20
Мы также можем узнать значение max
для каждой строки, удалив NA
, но это вернет -Inf
для строк со всеми NA
с
apply(df, 1,max, na.rm = TRUE)
#[1] 13 59 66 23 42 20 -Inf